1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.collect;
16
17 import static com.google.common.base.Preconditions.checkNotNull;
18 import static com.google.common.base.Preconditions.checkPositionIndex;
19
20 import com.google.common.annotations.GwtCompatible;
21 import com.google.common.base.Predicate;
22
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.Set;
30
31 import javax.annotation.Nullable;
32
33
34
35
36
37
38 @GwtCompatible
39 class FilteredKeyMultimap<K, V> extends AbstractMultimap<K, V> implements FilteredMultimap<K, V> {
40 final Multimap<K, V> unfiltered;
41 final Predicate<? super K> keyPredicate;
42
43 FilteredKeyMultimap(Multimap<K, V> unfiltered, Predicate<? super K> keyPredicate) {
44 this.unfiltered = checkNotNull(unfiltered);
45 this.keyPredicate = checkNotNull(keyPredicate);
46 }
47
48 @Override
49 public Multimap<K, V> unfiltered() {
50 return unfiltered;
51 }
52
53 @Override
54 public Predicate<? super Entry<K, V>> entryPredicate() {
55 return Maps.keyPredicateOnEntries(keyPredicate);
56 }
57
58 @Override
59 public int size() {
60 int size = 0;
61 for (Collection<V> collection : asMap().values()) {
62 size += collection.size();
63 }
64 return size;
65 }
66
67 @Override
68 public boolean containsKey(@Nullable Object key) {
69 if (unfiltered.containsKey(key)) {
70 @SuppressWarnings("unchecked")
71 K k = (K) key;
72 return keyPredicate.apply(k);
73 }
74 return false;
75 }
76
77 @Override
78 public Collection<V> removeAll(Object key) {
79 return containsKey(key) ? unfiltered.removeAll(key) : unmodifiableEmptyCollection();
80 }
81
82 Collection<V> unmodifiableEmptyCollection() {
83 if (unfiltered instanceof SetMultimap) {
84 return ImmutableSet.of();
85 } else {
86 return ImmutableList.of();
87 }
88 }
89
90 @Override
91 public void clear() {
92 keySet().clear();
93 }
94
95 @Override
96 Set<K> createKeySet() {
97 return Sets.filter(unfiltered.keySet(), keyPredicate);
98 }
99
100 @Override
101 public Collection<V> get(K key) {
102 if (keyPredicate.apply(key)) {
103 return unfiltered.get(key);
104 } else if (unfiltered instanceof SetMultimap) {
105 return new AddRejectingSet<K, V>(key);
106 } else {
107 return new AddRejectingList<K, V>(key);
108 }
109 }
110
111 static class AddRejectingSet<K, V> extends ForwardingSet<V> {
112 final K key;
113
114 AddRejectingSet(K key) {
115 this.key = key;
116 }
117
118 @Override
119 public boolean add(V element) {
120 throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
121 }
122
123 @Override
124 public boolean addAll(Collection<? extends V> collection) {
125 checkNotNull(collection);
126 throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
127 }
128
129 @Override
130 protected Set<V> delegate() {
131 return Collections.emptySet();
132 }
133 }
134
135 static class AddRejectingList<K, V> extends ForwardingList<V> {
136 final K key;
137
138 AddRejectingList(K key) {
139 this.key = key;
140 }
141
142 @Override
143 public boolean add(V v) {
144 add(0, v);
145 return true;
146 }
147
148 @Override
149 public boolean addAll(Collection<? extends V> collection) {
150 addAll(0, collection);
151 return true;
152 }
153
154 @Override
155 public void add(int index, V element) {
156 checkPositionIndex(index, 0);
157 throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
158 }
159
160 @Override
161 public boolean addAll(int index, Collection<? extends V> elements) {
162 checkNotNull(elements);
163 checkPositionIndex(index, 0);
164 throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
165 }
166
167 @Override
168 protected List<V> delegate() {
169 return Collections.emptyList();
170 }
171 }
172
173 @Override
174 Iterator<Entry<K, V>> entryIterator() {
175 throw new AssertionError("should never be called");
176 }
177
178 @Override
179 Collection<Entry<K, V>> createEntries() {
180 return new Entries();
181 }
182
183 class Entries extends ForwardingCollection<Entry<K, V>> {
184 @Override
185 protected Collection<Entry<K, V>> delegate() {
186 return Collections2.filter(unfiltered.entries(), entryPredicate());
187 }
188
189 @Override
190 @SuppressWarnings("unchecked")
191 public boolean remove(@Nullable Object o) {
192 if (o instanceof Entry) {
193 Entry<?, ?> entry = (Entry<?, ?>) o;
194 if (unfiltered.containsKey(entry.getKey())
195
196 && keyPredicate.apply((K) entry.getKey())) {
197 return unfiltered.remove(entry.getKey(), entry.getValue());
198 }
199 }
200 return false;
201 }
202 }
203
204 @Override
205 Collection<V> createValues() {
206 return new FilteredMultimapValues<K, V>(this);
207 }
208
209 @Override
210 Map<K, Collection<V>> createAsMap() {
211 return Maps.filterKeys(unfiltered.asMap(), keyPredicate);
212 }
213
214 @Override
215 Multiset<K> createKeys() {
216 return Multisets.filter(unfiltered.keys(), keyPredicate);
217 }
218 }